package com.yzh.dbrouter.config;

import com.yzh.dbrouter.DBRouterConfig;
import com.yzh.dbrouter.DBRouterJoinPoint;
import com.yzh.dbrouter.dynamic.DynamicDataSource;
import com.yzh.dbrouter.dynamic.DynamicMybatisPlugin;
import com.yzh.dbrouter.strategy.IDBRouterStrategy;
import com.yzh.dbrouter.strategy.impl.DBRouterStrategyImpl;
import com.yzh.dbrouter.util.PropertyUtil;
import org.apache.ibatis.plugin.Interceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 数据源配置解析
 */
@Configuration
@ConfigurationProperties(prefix = "mini-db-router.jdbc.datasource")
public class DataSourceAutoConfig implements EnvironmentAware {

    /**
     * 默认数据源配置
     */
    private Map<String, Object> defaultDataSourceConfig;
    /**
     * 数据源配置组
     */
    private Map<String, Map<String, Object>> dataSourceMap = new HashMap<>();
    /**
     * 分库数量
     */
    private int dbCount;
    /**
     * 分表数量
     */
    private int tbCount;
    /**
     * 路由字段
     */
    private String routerKey;
    @Bean(name = "db-router-point")
    @ConditionalOnMissingBean
    public DBRouterJoinPoint point(DBRouterConfig dbRouterConfig, IDBRouterStrategy dbRouterStrategy) {
        return new DBRouterJoinPoint(dbRouterConfig, dbRouterStrategy);
    }

    @Bean
    public DBRouterConfig dbRouterConfig() {
        return new DBRouterConfig(dbCount, tbCount, routerKey);
    }
    @Bean
    public Interceptor plugins() {
        return new DynamicMybatisPlugin();
    }
    @Bean
    public IDBRouterStrategy dbRouterStrategy(DBRouterConfig dbRouterConfig) {
        return new DBRouterStrategyImpl(dbRouterConfig);
    }
    @Bean
    public TransactionTemplate transactionTemplate(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(dataSourceTransactionManager);
        transactionTemplate.setPropagationBehaviorName("PROPAGATION_REQUIRED");
        return transactionTemplate;
    }

    /**
     * 创建数据源
     * 数据源创建完成后存放到DynamicDataSource中，它继承了AbstractRoutingDataSource，这个类里可以存放和读取相应的数据源信息
     * @return
     */
    @Bean
    public DataSource dataSource() {
        //数据源Map
        Map<Object, Object> targetDataSources = new HashMap<>();
        //获取数据源
        for (String dbInfo : dataSourceMap.keySet()) {
            Map<String, Object> objMap = dataSourceMap.get(dbInfo);
            targetDataSources.put(dbInfo, new DriverManagerDataSource(objMap.get("url").toString(), objMap.get("username").toString(), objMap.get("password").toString()));
        }
        //设置数据源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(new DriverManagerDataSource(
                defaultDataSourceConfig.get("url").toString(),
                defaultDataSourceConfig.get("username").toString(),
                defaultDataSourceConfig.get("password").toString()));
        return dynamicDataSource;
    }

    /**
     * 数据源配置提取
     * @param environment
     */
    @Override
    public void setEnvironment(Environment environment) {
        String prefix = "mini-db-router.jdbc.datasource.";

        dbCount = Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + "dbCount")));
        tbCount = Integer.parseInt(Objects.requireNonNull(environment.getProperty(prefix + "tbCount")));
        routerKey = Objects.requireNonNull(environment.getProperty(prefix + "routerKey"));
        //分库分表数据源
        String list = Objects.requireNonNull(environment.getProperty(prefix + "list"));
        for (String dbInfo : list.split(",")) {
            Map<String, Object> dataSourceProps = PropertyUtil.handle(environment, prefix + dbInfo, Map.class);
            dataSourceMap.put(dbInfo, dataSourceProps);
        }
        //默认数据源
        String defaultData = environment.getProperty(prefix + "default");
        defaultDataSourceConfig = PropertyUtil.handle(environment, prefix + defaultData, Map.class);
    }
}
